package vip.xiaonuo.vein.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.facedoor.modular.device.entity.DeviceCategory;
import vip.xiaonuo.facedoor.modular.devicebase.entity.DeviceBase;
import vip.xiaonuo.facedoor.modular.devicebase.service.DeviceBaseService;
import vip.xiaonuo.facedoor.modular.memberfeatures.entity.MemberFeatures;
import vip.xiaonuo.facedoor.modular.memberfeatures.service.MemberFeaturesService;
import vip.xiaonuo.facedoor.modular.memberuser.entity.MemberUser;
import vip.xiaonuo.facedoor.modular.memberuser.service.MemberUserService;
import vip.xiaonuo.vein.controller.vo.Feature;
import vip.xiaonuo.vein.controller.vo.UpdateFeatureInfo;
import vip.xiaonuo.vein.model.ResData;
import vip.xiaonuo.vein.modular.veindeviceevent.entity.VeinDeviceEvent;
import vip.xiaonuo.vein.modular.veindeviceevent.enums.VeinDeviceEventStatusEnum;
import vip.xiaonuo.vein.modular.veindeviceevent.service.VeinDeviceEventService;
import vip.xiaonuo.vein.modular.veinpalmdeviceuserrelate.entity.VeinPalmDeviceUserRelate;
import vip.xiaonuo.vein.modular.veinpalmdeviceuserrelate.enums.VeinPalmDeviceRelateStatusEnum;
import vip.xiaonuo.vein.modular.veinpalmdeviceuserrelate.service.VeinPalmDeviceUserRelateService;
import vip.xiaonuo.vein.websocket.ack.AckService;

import javax.annotation.Resource;
import javax.websocket.Session;
import java.util.List;
import java.util.Objects;

@Service("WsReplyService.class")
@Slf4j
public class WsReplyService {

    @Resource
    private HeartBeatService heartBeatService;

    @Resource
    private MemberUserService userService;

    @Resource
    private MemberFeaturesService featuresService;

    @Resource
    private DeviceBaseService deviceService;

    @Resource
    private VeinDeviceEventService eventService;

    @Resource
    private VeinPalmDeviceUserRelateService deviceUserRelateService;

    @Resource
    private AckService ackService;

    public void receiveMsg(String deviceNo,String message,Session session){
        if (message.contains("heartbeat")){// 心跳回复
            this.replyHeartBeat(deviceNo,message,session);
        }else if(message.contains("update_feature_info")){// 接收到特征值返回的处理
            if(this.saveFeature(deviceNo,message)){
                this.replayFeatureUpdate(message,session);
            }
        }else{
            // this.handleRequestStatus(deviceNo,message);
            ackService.ack(message);
        }
    }



    /**
     * 心跳回复
     * @param deviceNo
     * @param message
     * @param session
     */
    private void replyHeartBeat(String deviceNo,String message,Session session){
        String resp = heartBeatService.createSuccessResponse(message);
        if(resp!=null){
            if( this.sendOneMessage(session,resp)){
                // 更新设备数据状态
                heartBeatService.updateDevice(deviceNo,session);
            }
        }else{
            log.info("exception");
        }
    }

    /**
     * 特征值保存
     * @param deviceNo
     * @param message
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    protected boolean saveFeature(String deviceNo, String message) {
        DeviceBase deviceBase = deviceService.getOne(new LambdaQueryWrapper<DeviceBase>().eq(DeviceBase :: getRegistrationCode , deviceNo));

        if(deviceBase==null){
            log.debug("设备编号：{}对应的设备不存在",deviceNo);
            return false;
        }

        List<DeviceBase> palmDevices = deviceService.list(new LambdaQueryWrapper<DeviceBase>()
                .eq(DeviceBase :: getDeviceType , DeviceCategory.SUB_TYPE_PALM+""));

        try{
            UpdateFeatureInfo info = JSON.parseObject(message.substring(8), UpdateFeatureInfo.class);
            List<UpdateFeatureInfo.UpdateFeatureInfoDTO> userFeatures = info.getUpdateFeatureInfo();
            for(UpdateFeatureInfo.UpdateFeatureInfoDTO feature : userFeatures){
                String uuid = feature.getUserUuid();

                MemberUser user = userService.getById(uuid.substring(1));
                if(user == null ){
                    log.debug("人员编号：{}对应的人员不存在",uuid);
                    continue;
                }

                Feature f = new Feature(feature);
                String feature_str = f.toJsonString();

                // 保存或更新平台特征值
                MemberFeatures features = featuresService.getOne(new LambdaQueryWrapper<MemberFeatures>()
                    .eq(MemberFeatures :: getDwMemberUserId , user.getId())
                    .eq(MemberFeatures :: getPlatform , DeviceCategory.SUB_TYPE_PALM));
                if(features == null ){
                    features = new MemberFeatures();
                    features.setDwMemberUserId(user.getId());
                    features.setPlatform(DeviceCategory.SUB_TYPE_PALM);
                    features.setType(0);
                }
                features.setValue(feature_str);
                featuresService.saveOrUpdate(features);

                for(DeviceBase device : palmDevices){
                   this.createRelateInfo(user,device,deviceBase,Boolean.FALSE);
                }
            }
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 回复给设备处理结果
     * @param message
     * @param session
     */
    private void replayFeatureUpdate(String message, Session session) {
        String resp = heartBeatService.createSuccessResponse(message);
        if(resp!=null){
             this.sendOneMessage(session,resp);
        }else{
            log.info("exception");
        }
    }

    /**
     * 处理主动请求的数据的处理状态
     * @param deviceNo
     * @param message
     */
    private void handleRequestStatus(String deviceNo, String message) {
        if(message.length()<8){
            log.debug("返回数据无需处理：{}",message);
            return;
        }

        DeviceBase deviceBase = deviceService.getOne(new LambdaQueryWrapper<DeviceBase>()
                .eq(DeviceBase :: getRegistrationCode , deviceNo)
                .eq(DeviceBase :: getDeviceType , DeviceCategory.SUB_TYPE_PALM+""));

        if(deviceBase == null){
            log.debug("设备编号：{}对应的设备不存在",deviceNo);
            return;
        }

        String serialNo = message.substring(4,8);
        VeinPalmDeviceUserRelate relate = deviceUserRelateService.getOne(new LambdaQueryWrapper<VeinPalmDeviceUserRelate>()
                .eq(VeinPalmDeviceUserRelate :: getSn, serialNo)
                .eq(VeinPalmDeviceUserRelate :: getDeviceId , deviceBase.getId()));
        if(relate == null){
            log.debug("请求流水号：{}对应的待处理数据不存在",serialNo);
        }

        VeinDeviceEvent event = eventService.getOne(new LambdaQueryWrapper<VeinDeviceEvent>()
                .eq(VeinDeviceEvent :: getStatus , VeinDeviceEventStatusEnum.EXECUTE.getCode())
                .last("and serial_number like '%".concat(serialNo).concat("'")));

        if(event == null ){
            log.debug("请求流水号：{}对应的待处理事件不存在",serialNo);
        }
        try{
            String result = message.substring(8);
            ResData resData = JSON.parseObject(result, ResData.class);
            int resultCode = resData.getReturn_value();
            if (resultCode == 0){// 处理完成
                if(relate!=null )
                    relate.setStatus(VeinPalmDeviceRelateStatusEnum.DONE.getCode());
                if(event!=null )
                    event.setStatus(VeinDeviceEventStatusEnum.EXECUTE_SUCCESS.getCode());
            }else{ // 处理失败，记录失败原因
                String reason = AckService.resultCode.containsKey(resultCode)?AckService.resultCode.get(resultCode) : "未知错误";
                if(relate!=null ){
                    if(relate.getStatus() == VeinPalmDeviceRelateStatusEnum.ADD.getCode()) {
                        relate.setStatus(VeinPalmDeviceRelateStatusEnum.ADD_FAIL.getCode());
                    }else if(relate.getStatus() == VeinPalmDeviceRelateStatusEnum.UPDATE.getCode()){
                        relate.setStatus(VeinPalmDeviceRelateStatusEnum.UPDATE_FAIL.getCode());
                    }
                    relate.setResult(reason);
                }

                if(event!=null ){
                    event.setStatus(VeinDeviceEventStatusEnum.EXECUTE_ERROR.getCode());
                    event.setFailReason(reason);
                }
            }
            if(relate!=null ) deviceUserRelateService.updateById(relate);
            // 修改event表的数据
            if(event!=null ) eventService.updateById(event);
        }catch (Exception e){
            e.printStackTrace();
        }
    }


    private boolean sendOneMessage(Session session, String message) {
        if (session != null && session.isOpen()) {
            try {
                log.info("回复消息【{}】",message);
                session.getAsyncRemote().sendText(message);
                return true;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    public void createRelateInfo(MemberUser user,DeviceBase device,DeviceBase deviceBase,Boolean flag){
        VeinPalmDeviceUserRelate relate = deviceUserRelateService.getOne(new LambdaQueryWrapper<VeinPalmDeviceUserRelate>()
                .eq(VeinPalmDeviceUserRelate :: getUserId, user.getId())
                .eq(VeinPalmDeviceUserRelate :: getDeviceId , device.getId()));
        if(relate == null ){
            relate = new VeinPalmDeviceUserRelate();
            relate.setUserId(user.getId());
            relate.setDeviceId(device.getId());
            relate.setStatus(VeinPalmDeviceRelateStatusEnum.ADD.getCode());
        }else{
            relate.setStatus(VeinPalmDeviceRelateStatusEnum.UPDATE.getCode());
            if (flag){
                relate.setStatus(VeinPalmDeviceRelateStatusEnum.ADD.getCode());
            }
        }
        if(deviceBase!=null && Objects.equals(deviceBase.getId(), device.getId())){ // 从某设备上返回的特征值,该设备的关联数据状态直接保存成完成
            relate.setStatus(VeinPalmDeviceRelateStatusEnum.DONE.getCode());
        }
        relate.setSn("");
        deviceUserRelateService.saveOrUpdate(relate);
    }

}
